﻿using MiniFox.Components;
using MiniFox.Data.EntityFramework;
using MiniFox.Platform;
using MiniFox.Platform.Applications.Models;
using MiniFox.Platform.Applications.Providers;
using Newtonsoft.Json.Linq;
using System.Globalization;

namespace Platform.Data
{
    /// <summary>
    /// 
    /// </summary>
    [AutoResolve]
    public class DesktopProvider : EntityDataProvider<PlatformDbContext>, IDesktopProvider
    {
        private string[] GetUserRoles(string userId)
        {
            var roles = (from r in this.CurrentDbContext.SysUserRole where r.UserId == userId select r.RoleId).ToArray();
            return roles;
        }

        private string[] GetUserModules(string userId)
        {
            var modules = (from rm in this.CurrentDbContext.SysRoleModule
                         join ru in this.CurrentDbContext.SysUserRole on rm.RoleId equals ru.RoleId
                         where ru.UserId == userId select rm.ModuleId).Distinct().ToArray();
            return modules;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="identity"></param>
        /// <returns></returns>
        public SystemUser GetSystemUser(string userId)
        {
            if (string.IsNullOrEmpty(userId))
                return null;

            var user = this.CurrentDbContext.SysUser.SingleOrDefault(u => u.UserId == userId);
            if (user == null)
            {
                return null;
                //user = new SysUser
                //{
                //    UserId = identity.GlobalID,
                //    DisplayName = identity.DisplayName,
                //    LoginName = identity.Name,
                //    SecEmail = identity.SecEmail,
                //    Cellphone = identity.Cellphone,
                //    UserStatus = identity.Status.ToString(),
                //    CreateTime = DateTime.Now,
                //    UpdateTime = DateTime.Now
                //};
                //this.Insert(user);
            }
            else
            {
                //user.LoginName = identity.Name;
                //user.DisplayName = identity.DisplayName;
                //user.SecEmail = identity.SecEmail;
                //user.Cellphone = identity.Cellphone;
                //user.UserStatus = identity.Status.ToString();
                //user.UpdateTime = DateTime.Now;
                //this.Update(user);
            }
            var config = this.CurrentDbContext.SysUserConfig.SingleOrDefault(c => c.UserId == userId);
            if (config == null)
            {
                config = new SysUserConfig
                {
                    UserId = userId,
                    TimeZone = TimeZoneInfo.Local.Id,
                    Region = CultureInfo.CurrentCulture.Name,
                    ConfigData = "{}"
                };

                this.Insert(config);
            }
            return new SystemUser
            {
                UserID = user.UserId,
                SignName = user.LoginName,
                Cellphone = user.Cellphone,
                DisplayName = user.DisplayName,
                SecEmail = user.SecEmail,
                Icon = null,
                Status = Enum.Parse<IdentityStatus>(user.UserStatus),
                Settings = new UserSettings
                {
                    TimeZoneID = config.TimeZone,
                    RegionCode = config.Region,
                    Data = JToken.Parse(config.ConfigData)
                }
            };
        }

        #region shortcut
        public bool CreateShortcut(SystemUser user, SystemNavModule module)
        {
            SysUserShortcut shortcut = new();
            shortcut.ModuleId = module.ID;
            shortcut.UserId = user.UserID;
            return this.Insert(shortcut) > 0;
        }

        public bool RemoveShortcut(SystemUser user, SystemNavModule module)
        {
            var shortcut = this.CurrentDbContext.SysUserShortcut.SingleOrDefault(s => s.UserId == user.UserID && s.ModuleId == module.ID);

            return this.Delete(shortcut) > 0;
        }

        public IEnumerable<Shortcut> GetUserShortcuts(SystemUser user)
        {
            IEnumerable<Shortcut> shortcuts = (from s in this.CurrentDbContext.SysUserShortcut
                                               join m in this.CurrentDbContext.SysModule on s.ModuleId equals m.ModuleId
                                               where s.UserId == user.UserID
                                               select new Shortcut
                                               {
                                                   ModuleID = m.ModuleId,
                                                   ShortcutName = m.ModuleName,
                                                   ShortcutURI = m.ModuleUri
                                               }).ToArray();
            return shortcuts;
        }
        #endregion

        #region menu
        public IEnumerable<SystemNavBase> GetMenu(string appId)
        {
            List<SystemNavBase> menuData = new List<SystemNavBase>();
            var menus = (from m in this.CurrentDbContext.SysMenu
                         where m.AppId == appId
                         select new SystemNavGroup
                         {
                             ApplicationID = m.AppId,
                             SuperID = m.ParentId,
                             ID = m.MenuId,
                             Icon = m.Icon,
                             Label = m.Label,
                             Name = m.MenuName,
                             Ordinal = m.Ordinal ?? 0,
                         }).ToArray();

            var modules = (from m in this.CurrentDbContext.SysModule
                           join a in this.CurrentDbContext.SysApp on m.AppId equals a.AppId
                           join mm in this.CurrentDbContext.SysMenuModule on m.ModuleId equals mm.ModuleId
                           where m.AppId == appId && m.Enabled == true
                           select new SystemNavModuleEntry
                           {
                               ApplicationID = m.AppId,
                               Host = a.Host,
                               ID = m.ModuleId,
                               SuperID = mm.MenuId,
                               Name = m.ModuleName,
                               Icon = m.Icon,
                               OpenMode = Enum.Parse<OpenMode>(m.OpenMode),
                               Label = mm.Label,
                               Ordinal = mm.Ordinal ?? 0,
                               Port = a.Port,
                               QueryString = m.QueryString,
                               RequireSSL = a.Ssl,
                               RootPath = a.Path,
                               Url = m.ModuleUri
                           }).ToArray();

            var links = (from l in this.CurrentDbContext.SysMenuLink
                         where l.AppId == appId
                         select new SystemNavLink
                         {
                             ApplicationID = l.AppId,
                             ID = l.LinkId,
                             Icon = l.Icon,
                             Label = l.Label,
                             Name = l.LinkName,
                             OpenMode = Enum.Parse<OpenMode>(l.OpenMode),

                         }).ToArray();

            menuData.AddRange(menus);
            menuData.AddRange(modules);
            menuData.AddRange(links);

            return menuData;
        }

        public IEnumerable<SystemNavBase> GetMenu(string appId, SystemUser user)
        {
            var roles = this.GetUserRoles(user.UserID);
            List<SystemNavBase> menuData = new List<SystemNavBase>();
            var menus = (from m in this.CurrentDbContext.SysMenu
                         where m.AppId == appId
                         select new SystemNavGroup
                         {
                             ApplicationID = m.AppId,
                             SuperID = m.ParentId,
                             ID = m.MenuId,
                             Icon = m.Icon,
                             Label = m.Label,
                             Name = m.MenuName,
                             Ordinal = m.Ordinal ?? 0,
                         }).ToArray();

            var modules = (from m in this.CurrentDbContext.SysModule
                           join a in this.CurrentDbContext.SysApp on m.AppId equals a.AppId
                           join mm in this.CurrentDbContext.SysMenuModule on m.ModuleId equals mm.ModuleId
                           join rm in this.CurrentDbContext.SysRoleModule on m.ModuleId equals rm.ModuleId
                           where m.AppId == appId && m.Enabled == true && (m.IsPublic || roles.Contains(rm.RoleId))
                           select new SystemNavModuleEntry
                           {
                               ApplicationID = m.AppId,
                               Host = a.Host,
                               ID = m.ModuleId,
                               SuperID = mm.MenuId,
                               Name = m.ModuleName,
                               Icon = m.Icon,
                               OpenMode = Enum.Parse<OpenMode>(m.OpenMode),
                               Label = mm.Label,
                               Ordinal = mm.Ordinal ?? 0,
                               Port = a.Port,
                               QueryString = m.QueryString,
                               RequireSSL = a.Ssl,
                               RootPath = a.Path,
                               Url = m.ModuleUri
                           }).ToArray();

            var links = (from l in this.CurrentDbContext.SysMenuLink
                         where l.AppId == appId
                         select new SystemNavLink
                         {
                             ApplicationID = l.AppId,
                             ID = l.LinkId,
                             Icon = l.Icon,
                             Label = l.Label,
                             Name = l.LinkName,
                             OpenMode = Enum.Parse<OpenMode>(l.OpenMode),

                         }).ToArray();

            menuData.AddRange(menus);
            menuData.AddRange(modules);
            menuData.AddRange(links);

            return menuData;
        }
        #endregion

        #region navigation
        public IEnumerable<SystemNavBase> GetNavigation(string appId)
        {
            List<SystemNavBase> navData = new List<SystemNavBase>();
            var navs = (from n in this.CurrentDbContext.SysNav
                         where n.AppId == appId
                         select new SystemNavGroup
                         {
                             ApplicationID = n.AppId,
                             SuperID = n.ParentId,
                             ID = n.NavId,
                             Icon = n.Icon,
                             Label = n.Label,
                             Name = n.NavName,
                             Ordinal = n.Ordinal ?? 0,
                         }).ToArray();

            var modules = (from m in this.CurrentDbContext.SysModule
                           join a in this.CurrentDbContext.SysApp on m.AppId equals a.AppId
                           join nm in this.CurrentDbContext.SysNavModule on m.ModuleId equals nm.ModuleId
                           where m.AppId == appId && m.Enabled == true
                           select new SystemNavModuleEntry
                           {
                               ApplicationID = m.AppId,
                               Host = a.Host,
                               ID = m.ModuleId,
                               SuperID = nm.NavId,
                               Name = m.ModuleName,
                               Icon = m.Icon,
                               OpenMode = Enum.Parse<OpenMode>(m.OpenMode),
                               Label = nm.Label,
                               Ordinal = nm.Ordinal ?? 0,
                               Port = a.Port,
                               QueryString = m.QueryString,
                               RequireSSL = a.Ssl,
                               RootPath = a.Path,
                               Url = m.ModuleUri
                           }).ToArray();

            var links = (from l in this.CurrentDbContext.SysNavLink
                         where l.AppId == appId
                         select new SystemNavLink
                         {
                             ApplicationID = l.AppId,
                             ID = l.LinkId,
                             Icon = l.Icon,
                             Label = l.Label,
                             Name = l.LinkName,
                             OpenMode = Enum.Parse<OpenMode>(l.OpenMode),

                         }).ToArray();

            navData.AddRange(navs);
            navData.AddRange(modules);
            navData.AddRange(links);

            return navData;
        }

        public IEnumerable<SystemNavBase> GetNavigation(string appId, SystemUser user)
        {
            var roles = this.GetUserRoles(user.UserID);
            List<SystemNavBase> navData = new List<SystemNavBase>();
            var navs = (from n in this.CurrentDbContext.SysNav
                        where n.AppId == appId
                        select new SystemNavGroup
                        {
                            ApplicationID = n.AppId,
                            SuperID = n.ParentId,
                            ID = n.NavId,
                            Icon = n.Icon,
                            Label = n.Label,
                            Name = n.NavName,
                            Ordinal = n.Ordinal ?? 0,
                        }).ToArray();

            var modules = (from m in this.CurrentDbContext.SysModule
                           join a in this.CurrentDbContext.SysApp on m.AppId equals a.AppId
                           join nm in this.CurrentDbContext.SysNavModule on m.ModuleId equals nm.ModuleId
                           join rm in this.CurrentDbContext.SysRoleModule on m.ModuleId equals rm.ModuleId
                           where m.AppId == appId && m.Enabled == true && (m.IsPublic || roles.Contains(rm.RoleId))
                           select new SystemNavModuleEntry
                           {
                               ApplicationID = m.AppId,
                               Host = a.Host,
                               ID = m.ModuleId,
                               SuperID = nm.NavId,
                               Name = m.ModuleName,
                               Icon = m.Icon,
                               OpenMode = Enum.Parse<OpenMode>(m.OpenMode),
                               Label = nm.Label,
                               Ordinal = nm.Ordinal ?? 0,
                               Port = a.Port,
                               QueryString = m.QueryString,
                               RequireSSL = a.Ssl,
                               RootPath = a.Path,
                               Url = m.ModuleUri
                           }).ToArray();

            var links = (from l in this.CurrentDbContext.SysNavLink
                         where l.AppId == appId
                         select new SystemNavLink
                         {
                             ApplicationID = l.AppId,
                             ID = l.LinkId,
                             Icon = l.Icon,
                             Label = l.Label,
                             Name = l.LinkName,
                             OpenMode = Enum.Parse<OpenMode>(l.OpenMode),

                         }).ToArray();

            navData.AddRange(navs);
            navData.AddRange(modules);
            navData.AddRange(links);

            return navData;
        }
        #endregion

        #region app
        private IQueryable<SystemApp> QueryApps()
        {
            return (from a in this.CurrentDbContext.SysApp
                    where a.Enabled == true
                    select new SystemApp
                    {
                        AppID = a.AppId,
                        AppName = a.AppName,
                        RequireSSL = a.Ssl,
                        Host = a.Host,
                        Port = a.Port,
                        Path = a.Path,
                        Icon = a.Icon
                    });
        }
        public IEnumerable<SystemApp> GetSystemApps()
        {
            var list = QueryApps().ToArray();
            return list;
        }

        public IEnumerable<SystemApp> GetSystemApps(SystemUser user)
        {
            var array = (from rm in this.CurrentDbContext.SysRoleModule
                           join ru in this.CurrentDbContext.SysUserRole on rm.RoleId equals ru.RoleId
                           join am in this.CurrentDbContext.SysModule on rm.ModuleId equals am.ModuleId
                           where ru.UserId == user.UserID
                           select am.AppId).Distinct();
            return QueryApps().Where(a => array.Contains(a.AppID));
        }

        #endregion

        public IEnumerable<SystemNavModule> SearchModules(SystemUser user, string keyword)
        {
            var roles = this.GetUserRoles(user.UserID);
            var modules = (from m in this.CurrentDbContext.SysModule
                           join a in this.CurrentDbContext.SysApp on m.AppId equals a.AppId
                           join rm in this.CurrentDbContext.SysRoleModule on m.ModuleId equals rm.ModuleId
                           where m.Enabled == true && roles.Contains(rm.RoleId)
                           select new SystemNavModuleEntry
                           {
                               ApplicationID = m.AppId,
                               Host = a.Host,
                               ID = m.ModuleId,
                               Name = m.ModuleName,
                               Icon = m.Icon,
                               OpenMode = Enum.Parse<OpenMode>(m.OpenMode),
                               Port = a.Port,
                               QueryString = m.QueryString,
                               RequireSSL = a.Ssl,
                               RootPath = a.Path,
                               Url = m.ModuleUri
                           });
            return modules.Distinct().ToArray();
        }

        public Organization GetOrganization(string orgId)
        {
            var org = this.CurrentDbContext.SysOrganization.SingleOrDefault(o => o.OrgId == orgId);
            if (org == null)
                return null;
            return new Organization
            {
                ID = org.OrgId,
                Name = org.OrgName,
                DisplayName = org.DisplayName,
                Description = org.Description,
                Icon = org.Icon,
                //DefaultTheme = org.DefaultTheme,
                Logo = org.Logo
            };
        }
    }
}
